package com.zijidelu.luframework.infrastructure.persistence.repository.core.data;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.base.AbstractRepository;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;

/**
 * 抽象数据处理器。
 *
 * @author ZIJIDELU
 * @date: 2024/3/21 22:06
 */
public abstract class AbstractDataProcessor<
        P extends PO,
        D extends DataModel
        > extends AbstractRepository<P, D> implements DataProcessor<P, D> {
    @Setter(onMethod_ = {@Autowired})
    private TransactionTemplate transactionTemplate;

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean existById(Serializable id) {
        if (Objects.isNull(id)) {
            return false;
        }

        return getPersistenceContext().getMybatisPlusService().exists(getPersistenceContext().getBaseLambdaQueryWrapper().eq(P::getId, id));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public D findById(Serializable id) {
        if (Objects.isNull(id)) {
            return null;
        }

        return getDataConverter().poToData(getPersistenceContext().getMybatisPlusService().getById(id));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public D findById(Serializable id, Consumer<LambdaQueryWrapper<P>> lambdaQueryWrapperConsumer) {
        if (Objects.isNull(id)) {
            return null;
        }

        final LambdaQueryWrapper<P> baseLambdaQueryWrapper = getPersistenceContext().getBaseLambdaQueryWrapper();
        if (Objects.nonNull(lambdaQueryWrapperConsumer)) {
            lambdaQueryWrapperConsumer.accept(baseLambdaQueryWrapper);
        }
        baseLambdaQueryWrapper.eq(P::getId, id);

        return getDataConverter().poToData(getPersistenceContext().getMybatisPlusService().getOne(baseLambdaQueryWrapper));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<D> findBatchById(Collection<Serializable> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }

        return getDataConverter().poToDataList(getPersistenceContext().getMybatisPlusService().listByIds(ids));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<D> query(Consumer<LambdaQueryChainWrapper<P>> lambdaQueryChainWrapperConsumer) {
        if (Objects.isNull(lambdaQueryChainWrapperConsumer)) {
            return Collections.emptyList();
        }

        final LambdaQueryChainWrapper<P> wrapper = getPersistenceContext().getBaseLambdaQueryChainWrapper();
        lambdaQueryChainWrapperConsumer.accept(wrapper);
        return getDataConverter().poToDataList(wrapper.list());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<D> query(Wrapper<P> queryWrapper) {
        if (Objects.isNull(queryWrapper)) {
            return Collections.emptyList();
        }
        return getDataConverter().poToDataList(getPersistenceContext().getMybatisPlusService().list(queryWrapper));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean saveOne(final D dto) {
        if (Objects.isNull(dto)) {
            return true;
        }

        // 数据模型生命周期 - 预保存
        dto.onPreSave();

        final P entityInsert = getDataConverter().dataToPo(dto);
        final boolean saveResult = getPersistenceContext().getMybatisPlusService().save(entityInsert);
        if (saveResult && Objects.nonNull(entityInsert.getId())) {
            // 保存成功后回写 ID
            dto.setId(entityInsert.getId());
        }

        return saveResult;
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveBatch(Collection<D> dtoColl) {
        if (CollectionUtils.isEmpty(dtoColl)) {
            return true;
        }

        final List<D> dataList = dtoColl instanceof ArrayList<D> ? (List<D>) dtoColl : new ArrayList<>(dtoColl);
        final List<P> poList = new ArrayList<>(dtoColl.size());
        for (D dto : dataList) {
            // 数据模型生命周期 - 预保存
            dto.onPreSave();
            poList.add(getDataConverter().dataToPo(dto));
        }

        // 批量保存
        final boolean isSaveBatch = getPersistenceContext().getMybatisPlusService().saveBatch(poList);
        // entityList 与 dtoColl 数量一致，元素顺序一致
        if (isSaveBatch) {
            for (int i = 0; i < dataList.size(); i++) {
                D data = dataList.get(i);
                P po = poList.get(i);
                data.setId(po.getId());
            }
        }

        return isSaveBatch;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean updateById(D dto) {
        if (Objects.isNull(dto)) {
            return true;
        }

        if (Objects.isNull(dto.getId())) {
            throw new IllegalArgumentException("ID cannot be null: " + dto);
        }

        // 数据模型生命周期 - 预更新
        dto.onPreUpdate();

        return getPersistenceContext().getMybatisPlusService()
                .updateById(getDataConverter().dataToPo(dto));
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateBatchById(Collection<D> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return true;
        }

        final List<P> entityList = new ArrayList<>(dtoList.size());
        for (D dto : dtoList) {
            if (Objects.isNull(dto.getId())) {
                throw new IllegalArgumentException("ID cannot be null: " + dto);
            }

            // 数据模型生命周期 - 预更新
            dto.onPreUpdate();
            entityList.add(getDataConverter().dataToPo(dto));
        }

        // 批量更新
        return getPersistenceContext().getMybatisPlusService().updateBatchById(entityList);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean deleteById(Serializable id) {
        if (Objects.isNull(id)) {
            return true;
        }

        return getPersistenceContext().getMybatisPlusService().removeById(id);
    }

    @Override
    public boolean deleteWithLambda(Consumer<LambdaQueryWrapper<P>> lambdaQueryWrapperConsumer) {
        LambdaQueryWrapper<P> baseLambdaQueryWrapper = getPersistenceContext().getBaseLambdaQueryWrapper();
        lambdaQueryWrapperConsumer.accept(baseLambdaQueryWrapper);
        // 执行删除操作
        return getPersistenceContext().getMybatisPlusService().remove(baseLambdaQueryWrapper);
    }

    @Override
    public boolean delete(Consumer<QueryWrapper<P>> queryWrapperConsumer) {
        QueryWrapper<P> baseQueryWrapper = getPersistenceContext().getBaseQueryWrapper();
        queryWrapperConsumer.accept(baseQueryWrapper);
        // 执行删除操作
        return getPersistenceContext().getMybatisPlusService().remove(baseQueryWrapper);
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteBatchById(Collection<Serializable> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return true;
        }

        return getPersistenceContext().getMybatisPlusService().removeBatchByIds(ids);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean saveOrUpdateBatch(Collection<D> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return true;
        }

        final List<D> saveList = new ArrayList<>();
        final List<D> updateList = new ArrayList<>();
        for (D data : dataList) {
            if (data.getId() == null) {
                // ID为空，新增
                saveList.add(data);
            } else {
                // ID不为空，更新
                updateList.add(data);
            }
        }

        return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
            final boolean saveResult;
            if (saveList.isEmpty()) {
                saveResult = true;
            } else {
                saveResult = saveBatch(saveList);
            }
            final boolean updateResult;
            if (updateList.isEmpty()) {
                updateResult = true;
            } else {
                updateResult = updateBatchById(updateList);
            }
            // 保存与更新没有同时成功，回滚事务
            if (!(saveResult && updateResult)) {
                status.setRollbackOnly();
            }

            return saveResult && updateResult;
        }));

    }
}
